#!/usr/bin/python

import sys
from opencv.cv import *
from opencv.highgui import *
from min_quad import min_quad

def draw_lines(to, lines, rgb, width):
    for line in lines:
        cvLine(to, line[0], line[1], CV_RGB(*rgb), width, CV_AA)

def draw_polygon(to, points, rgb, width):
    p = points[-1]
    for q in points:
        cvLine(to, p, q, CV_RGB(*rgb), width, CV_AA)
        p = q

def draw_points(to, points, rgb, width):
    for p in points:
        cvCircle(to, p, width, CV_RGB(*rgb), CV_FILLED, 8)

def hough_lines(img, storage):
    W, H = img.width, img.height

    # original values
    # rho = 1
    # theta = CP_PI/180.0
    # threshold = 25
    # minimum_line_length = 150
    # maximum_gap = 25
    
    method = CV_HOUGH_PROBABILISTIC
    rho = 1
    theta = CV_PI/180.0
    threshold = 25  # W * H * 0.001  (?)
    minimum_line_length = 150  # min(W, H) * 0.1  (?)
    maximum_gap = 25  # min(W, H) * 0.01  (?)

    lines = cvHoughLines2(img, storage,
                          method, rho, theta,
                          threshold, minimum_line_length, maximum_gap)
    return [ (l[0], l[1]) for l in lines ]

def convex_hull(points):
    hull = cvConvexHull2(points, CV_COUNTER_CLOCKWISE, 0)
    return [ points[i] for i in hull ]

def coverdetect(fname):
    src = cvLoadImage(fname, 0)
    dst = cvCreateImage(cvGetSize(src), 8, 1)
    dstcolor = cvCreateImage(cvGetSize(src), 8, 3)
    storage = cvCreateMemStorage(0)

    # TODO(nilton): try a gaussian smoothing before using canny
    #dstgaussian = cvCreateImage(cvGetSize(src), 8, 1)
    #cvSmooth(src, dstgaussian, CV_GAUSSIAN, 5, 5, 0.4)
    #cvSaveImage('source.jpg', src)
    #cvSaveImage('gaussian.jpg', dstgaussian)
    #src = dstgaussian

    # TODO(nilton): try with other edge detection algorithms
    cvCanny(src, dst, 50, 200, 3)
    

    cvCvtColor(dst, dstcolor, CV_GRAY2BGR)

    lines = hough_lines(dst, storage)
    draw_lines(dstcolor, lines, (255, 0, 0), 1)

    hull = convex_hull([ l[0] for l in lines ] + [ l[1] for l in lines ])
    draw_polygon(dstcolor, hull, (0, 255, 0), 2)

    quad = min_quad([ (p.x, p.y) for p in hull ])
    quad = [cvPoint(x, y) for (x, y) in  quad]
    draw_polygon(dstcolor, quad, (0, 0, 255), 2)

    cvNamedWindow("Output")
    cvShowImage("Output", dstcolor)
    cvWaitKey(0)
    cvSaveImage('cover.jpg', dstcolor)

    quad.sort(key=lambda p: p.x)
    ul, ll, ur, lr = quad  # first guess
    if ul.y > ll.y:
        ul, ll = ll, ul
    if ur.y > lr.y:
        ur, lr = lr, ur

    # TODO: make these a percentage of image size (?)
    ul.x += 5
    ll.x += 5
    ur.x -= 5
    lr.x -= 5
    ul.y += 5
    ur.y += 5
    ll.y -= 5
    lr.y -= 5

    return tuple( (p.x, p.y) for p in (ul, ll, lr, ur) )

if __name__ == '__main__':
    print coverdetect(sys.argv[1])
